/*路径相关工具函数包，提供路径判断、分割及文件信息扩展功能*/
package rpath

import (
	"os"
	"path/filepath"
)

// IsDir 判断指定路径是否为目录
// 参数path：待判断的文件或目录路径（绝对路径或相对路径）
// 返回值：如果路径存在且为目录则返回true，否则返回false
// 说明：内部通过os.Stat获取路径信息，若获取失败（如路径不存在）也会返回false
func IsDir(path string) bool {
	info, err := os.Stat(path)
	return err == nil && info.IsDir()
}

// IsFile 判断指定路径是否为普通文件
// 参数path：待判断的文件或目录路径（绝对路径或相对路径）
// 返回值：如果路径存在且为普通文件则返回true，否则返回false
// 说明：内部通过os.Stat获取路径信息，若获取失败（如路径不存在）也会返回false
func IsFile(path string) bool {
	info, err := os.Stat(path)
	return err == nil && !info.IsDir()
}

// Split 将路径分割为目录、文件名、文件名主体和文件后缀
// 参数path：待分割的文件路径（支持任意合法路径格式）
// 返回值：
//
//	dir：路径中的目录部分（以路径分隔符结尾，如"/home/user/"或"dir/"）
//	filesource：路径中的完整文件名（包含后缀，如"image.png"）
//	name：文件名主体（不含后缀，如"image"）
//	ext：文件后缀（含小数点，如".png"，无后缀则为空字符串）
//
// 说明：
//  1. 对于无后缀的文件（如"README"），name为完整文件名，ext为空
//  2. 对于仅有后缀的文件（如".bashrc"），name为空，ext为".bashrc"
//  3. 路径分隔符会自动适配当前操作系统（/或\）
func Split(path string) (dir, file, name, ext string) {
	// 先使用filepath.Split分割出目录和文件名
	dir, file = filepath.Split(path)

	// 从文件名末尾向前查找最后一个小数点，区分文件名主体和后缀
	for i := len(file) - 1; i >= 0 && !os.IsPathSeparator(file[i]); i-- {
		if file[i] == '.' {
			name = file[:i] // 小数点前的部分作为文件名主体
			ext = file[i:]  // 小数点及之后的部分作为后缀
			return          // 找到后立即返回
		}
	}

	// 若未找到小数点（无后缀），则文件名主体为完整文件名，后缀为空
	name = file
	ext = ""
	return
}

// FileInfo 扩展os.FileInfo接口，新增IsFile方法用于判断是否为普通文件
// 继承os.FileInfo的所有方法（Name、Size、Mode、ModTime、IsDir、Sys）
type FileInfo interface {
	os.FileInfo
	// IsFile 判断当前文件信息是否对应普通文件
	IsFile() bool
}

// fileStat 是FileInfo接口的实现类型，封装os.FileInfo并实现IsFile方法
type fileStat struct {
	os.FileInfo // 嵌入os.FileInfo，继承其所有方法实现
}

// Stat 获取指定路径的文件信息，并返回扩展的FileInfo接口实例
// 参数path：待获取信息的文件或目录路径
// 返回值：
//
//	FileInfo：扩展的文件信息接口实例，包含IsFile方法
//	error：获取信息失败时返回的错误（如路径不存在、权限不足等）
//
// 说明：内部调用os.Stat获取原始文件信息，再包装为fileStat类型
func Stat(path string) (FileInfo, error) {
	info, err := os.Stat(path)
	if err != nil {
		return nil, err
	}

	return &fileStat{FileInfo: info}, nil
}

// IsFile 实现FileInfo接口的IsFile方法，判断是否为普通文件
// 返回值：如果是普通文件则返回true，目录或其他类型文件返回false
// 说明：通过判断!IsDir()实现（非目录即为普通文件）
func (fs *fileStat) IsFile() bool {
	return !fs.IsDir()
}
